package tako.wisers.com.android.apis.location;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import tako.wisers.com.android.apis.R;
import tako.wisers.com.android.apis.http.HttpGeter;
import tako.wisers.com.android.apis.location.overlay.RouteOverlay;
import tako.wisers.com.android.apis.location.overlay.PointOverlay;
import tako.wisers.com.android.apis.util.Configration;
import tako.wisers.com.android.apis.util.Global;

import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.Drawable;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

public class RouteDrawer {
	private GeoPoint mStartPoint;
	private GeoPoint mEndPoint;
	private static final String URL = Configration.getInstance().getProperty(
			Global.ROUTE_SERVICE_KEY);
	private static final String KML_CHARSET = "UTF-8";

	private MapView mMapView;
	private OverlayControl mOverlayControl;
	private Double mSumDistance;
	private int mRouteMode;
	private String mRouteText;
	private Drawable mEndMark;

	public RouteDrawer(Activity activity, GeoPoint startPoint,
			GeoPoint endPoint, MapView mapView) {
		mStartPoint = startPoint;
		mEndPoint = endPoint;
		mMapView = mapView;
		mMapView.getOverlays().clear();
		
		mEndMark = activity.getResources().getDrawable(R.drawable.map_pin_e);
		final int intrinsicWidth = mEndMark.getIntrinsicWidth();
		final int intrinsicHeight = mEndMark.getIntrinsicHeight();
		mEndMark.setBounds(0, 0, intrinsicWidth, intrinsicHeight);

		mRouteMode = activity.getIntent().getIntExtra(Global.ROUTE_MODE,
				R.id.drive_route);
		mOverlayControl = new OverlayControl(mapView);
		mOverlayControl.build(activity);
	}

	public boolean draw() {
		try {
			InputStream kmlInput = getKMLInputStream();
			if (kmlInput == null) {
				return false;
			}
			parser(kmlInput);
			IOUtils.closeQuietly(kmlInput);
			return true;
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return false;
	}

	private InputStream getKMLInputStream() {
		String startLac = int2double(mStartPoint.getLatitudeE6()) + ","
				+ int2double(mStartPoint.getLongitudeE6());
		String endLac = int2double(mEndPoint.getLatitudeE6()) + ","
				+ int2double(mEndPoint.getLongitudeE6());
		String url = null;
		switch (mRouteMode) {
		case R.id.walk_route:
			url = String.format(URL, startLac, endLac, Global.WALK_MODE,
					Global.WALK_FLAG);
			break;
		default:
			url = String.format(URL, startLac, endLac, Global.DRIVE_MODE,
					Global.DRIVE_FLAG);
		}
		try {
			HttpGeter geter = new HttpGeter(url);
			if (geter.getResponseCode() != 200) {
				return null;
			}
			String str = geter.getContent();
			byte[] data = str.getBytes(KML_CHARSET);
			if (data.length < 10) {
				return null;
			}
			geter.close();

			return new ByteArrayInputStream(data);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	private void parser(InputStream is) throws ParserConfigurationException,
			SAXException, IOException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.parse(is);
		RouteDistanceCount disCount = new RouteDistanceCount();

		if (doc.getElementsByTagName("GeometryCollection").getLength() > 0) {
			// String path =
			// doc.getElementsByTagName("GeometryCollection").item(0).getFirstChild().getFirstChild().getNodeName();
			String path = doc.getElementsByTagName("GeometryCollection")
					.item(0).getFirstChild().getFirstChild().getFirstChild()
					.getNodeValue();
			String[] pairs = path.split(" ");
			String[] lngLat = pairs[0].split(","); // lngLat[0]=longitude
			// lngLat[1]=latitude
			// lngLat[2]=height
			GeoPoint startGP = new GeoPoint((int) (Double
					.parseDouble(lngLat[1]) * 1E6), (int) (Double
					.parseDouble(lngLat[0]) * 1E6));
			disCount.setPointOfRoute(mStartPoint, startGP);
			Drawable mark = mOverlayControl.getMarker();
			int xOffset = mOverlayControl.getMarkerXOffset();
			int yoffset = mOverlayControl.getMarkerYOffset();
			Overlay startOverlay = new PointOverlay(startGP, mark, xOffset,
					yoffset);
			mOverlayControl.setOverlay(startOverlay);
			GeoPoint gp1;
			GeoPoint gp2 = startGP;
			for (int i = 1; i < pairs.length; i++) // the last one would be
			// crash
			{
				lngLat = pairs[i].split(",");
				gp1 = gp2;
				// watch out! For GeoPoint, first:latitude, second:longitude
				gp2 = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6),
						(int) (Double.parseDouble(lngLat[0]) * 1E6));
				RouteOverlay overlay = new RouteOverlay(gp1, gp2, 2, Color.BLUE);
				mMapView.getOverlays().add(overlay);
				disCount.setPointOfRoute(gp1, gp2);
			}
			disCount.setPointOfRoute(gp2, mEndPoint);
			Overlay endOverlay = new PointOverlay(mEndPoint, mEndMark, xOffset,
					yoffset);
			mOverlayControl.setOverlay(endOverlay);
			mSumDistance = disCount.getDistance();
			String distanceText = mRouteMode == R.id.walk_route ? "Walk distance:"
					: "Drive distance:";
			mRouteText = distanceText + mSumDistance.toString() + "km";
			System.gc();
		}

	}
	
	public String getRouteText(){
		return mRouteText;
	}

	private double int2double(int loc) {
		return (double) loc / Global.MILLION;
	}
}
